pub fn fizz_buzz(n: i32) -> String {
    if n % 15 == 0 {
        "FizzBuzz".to_string()
    } else if n % 3 == 0 {
        "Fizz".to_string()
    } else if n % 5 == 0 {
        "Buzz".to_string()
    } else {
        n.to_string()
    }
}

pub fn math(op: fn(i32, i32) -> i32, a: i32, b: i32) -> i32 {
    op(a, b)
}

fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn sub(a: i32, b: i32) -> i32 {
    a - b
}

fn mul(a: i32, b: i32) -> i32 {
    a * b
}

fn div(a: i32, b: i32) -> i32 {
    a / b
}

fn is_even(n: i32) -> bool {
    n % 2 == 0
}

fn is_odd(n: i32) -> bool {
    n % 2 != 0
}

fn fn_check_even() -> fn(i32) -> bool {
    is_even
}

fn fn_check_odd() -> fn(i32) -> bool {
    is_odd
}

fn check_even(n: i32, f: fn(i32) -> bool) -> bool {
    f(n)
}

fn check_odd(n: i32, f: fn(i32) -> bool) -> bool {
    f(n)
}

//#![feature(const_fn)]
const fn init_len() -> usize {
    return 5;
}

fn main() {
    println!("Hello, world!");

    assert_eq!(fizz_buzz(1), "1");
    assert_eq!(fizz_buzz(3), "Fizz");
    assert_eq!(fizz_buzz(5), "Buzz");
    assert_eq!(fizz_buzz(15), "FizzBuzz");
    assert_eq!(fizz_buzz(25), "Buzz");

    let v = "hello world!";
    assert_eq!(v, "hello world!");
    let v2 = v.to_string();
    let v = "hello Rust!";
    assert_eq!(v2, "hello world!");
    assert_eq!(v, "hello Rust!");
    // 块级作用域， 拥有不同的生命周期
    {
        let v = "hello world!";
        assert_eq!(v, "hello world!");
    }
    assert_eq!(v, "hello Rust!");
    println!("{}", v2);

    let a = 2;
    let b = 3;
    assert_eq!(math(add, a, b), 5);
    assert_eq!(math(sub, a, b), -1);
    assert_eq!(math(mul, a, b), 6);
    assert_eq!(math(div, a, b), 0);
    let c = math(add, a, b);
    println!("{}", c);

    assert_eq!(check_even(a, is_even), true);
    assert_eq!(check_even(b, is_even), false);
    assert_eq!(check_odd(b, is_odd), true);

    assert_eq!(fn_check_even()(a), true);
    assert_eq!(fn_check_even()(b), false);
    assert_eq!(fn_check_odd()(b), true);

    let arr = [0; init_len()]; // 初始化为0，长度为5的数组
    assert_eq!(arr.len(), 5);

    // 闭包 closure
    let out = 42;
    // fn add(i: i32, j: i32) -> i32 { i + j + out} //Error [E0434]: can't capture dynamic environment in a fn item
    fn add_out(i: i32, j: i32) -> i32 {
        i + j
    }
    assert_eq!(3, add_out(1, 2));

    let closure_inferred = |i, j| i + j + out;
    assert_eq!(45, closure_inferred(1, 2));

    fn match_out(n: i32) -> () {
        // match
        match n {
            0 => println!("Nothing"),
            1..3 => println!("One two three"),
            5 | 7 | 11 | 13 => println!("Bad luck"),
            n @ 42 => println!("Answer is {}", n),
            _ => println!("Common"),
        }
    }

    match_out(0);
    match_out(3);
    match_out(13);
    match_out(63);
    match_out(43);
    match_out(42);
}
